﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ttlang.node;
using ttlang.semantic;

namespace ttlang.compiler
{
    internal static class compiler_expr
    {
        public static void ParseNode_Number(CompilerContext context, src.AstNode innode, out Node_Expr_Number outnode, bool inv = false)
        {

            NodeType nodetype = NodeType.CODE_COMMENT;
            string typestr = "";
            switch (innode.type)
            {
                case "INT":
                    nodetype = NodeType.INT;
                    typestr = "int32";
                    break;
                case "BIN":
                    nodetype = NodeType.INT_BIN;
                    break;
                case "HEX":
                    nodetype = NodeType.INT_HEX;
                    break;
                case "FLOAT":
                    nodetype = NodeType.FLOAT;
                    //typestr = "float";
                    break;
                default:
                    throw new Exception("not supported.");
            }
            SystemModule.ttlangCore.FindType(typestr, out TTType tttype);
            var v = new Node_Expr_Number(tttype);
            v.srcnumber = inv ? ("-" + innode.text) : innode.text;
            v.isConst = true;
            v.numbertype = nodetype;
            outnode = v;
        }
        public static void ParseNode_String(CompilerContext context, src.AstNode innode, out Node_Expr_String outnode)
        {
            SystemModule.ttlangCore.FindType("string", out TTType tttype);
            var v = new Node_Expr_String(tttype);
            outnode = v;
            v.value = innode.text;

        }
        public static void ParseNode_Bool(CompilerContext context, src.AstNode innode, out Node_Expr_Bool outnode)
        {
            SystemModule.ttlangCore.FindType("bool", out TTType tttype);
            var v = new Node_Expr_Bool(tttype);
            outnode = v;
            v.value = innode.text;

        }
        public static void ParseNode_Expr_Member(CompilerContext context, src.AstNode innode, out node.Node_Expr outnode)
        {
            //先试试看能不能处理为idchain
            var inleft = innode.children[0];
            if (inleft.type == "expr" && inleft.children.Count == 1)
                inleft = inleft.children[0];
            ParseNode_IDChain_OnlyExpr(context, inleft, out Node_Expr outleft);

            //脫殼只要函數名
            var inright = innode.children[2];
            if (inright.type == "expr" && inright.children.Count == 1)
                inright = inright.children[0];
            if (inright.type == "expr_call")
                inright = inright.children[0];
            if (outleft is node.Node_Expr_TempVar tempvar)
            {
                Node_Expr_Member member = new Node_Expr_Member();
                member.left = tempvar;
                //member.membername = inright.text;
                var tttype = tempvar.id.type;
                tttype.FindMember(inright.text, out var _vm);
                if (_vm == null)
                    throw new Exception("should not null.");
                member.member = _vm;
                outnode = member;

                ////临时变量.b
                ////有两个可能性，成员变量货成员函数，都是成员访问
                return;

            }
            if (outleft is node.Node_Expr_Container container) //Type.xxx // static member or type.type typechain
            {
                //先看看是不是成员访问
                if (container.container.FindMember(inright.text, out var _vm))
                {
                    Node_Expr_Member member = new Node_Expr_Member();
                    member.left = container;
                    member.member = _vm;
                    outnode = member;
                    return;
                }
                if (container.container.FindSubContainer(inright.text, out var _sc))
                {
                    Node_Expr_Container newcontainer = new Node_Expr_Container();
                    newcontainer.container = _sc;
                    outnode = newcontainer;
                    return;
                }
            }
            throw new NotSupportedException();

        }
        public static bool isConst(src.AstNode innode)
        {
            if (innode.type == "INT" ||
                innode.type == "FLOAT"
                ||
                innode.type == "HEX"
                ||
                innode.type == "BIN")

                return true;
            return false;
        }
        public static void ParseNode_Expr(CompilerContext context, src.AstNode innode, out node.Node_Expr outnode)
        {
            switch (innode.type)
            {
                case "number":
                case "INT":
                case "FLOAT":
                    {
                        ParseNode_Number(context, innode, out Node_Expr_Number _node);
                        outnode = _node;
                    }
                    return;
                case "STRING":
                    {
                        ParseNode_String(context, innode, out Node_Expr_String _node);
                        outnode = _node;
                    }
                    return;
                case "BOOL":
                    {
                        ParseNode_Bool(context, innode, out Node_Expr_Bool _node);
                        outnode = _node;

                    }
                    return;
                case "ID":
                case "INNERTYPE":
                    {
                        ParseNode_ID_OnlyExpr(context, innode, out outnode);
                    }
                    return;
                case "idchain":
                    {
                        ParseNode_IDChain_OnlyExpr(context, innode, out outnode);
                    }
                    return;
                case "expr_add":
                case "expr_mul":
                case "expr_shift":
                case "expr_relation":
                case "expr_equal":
                case "expr_and":
                case "expr_xor":
                case "expr_or":
                case "expr_logicand":
                case "expr_logicor":
                    {
                        var math = new Node_Expr_Math();
                        math.token = innode.children[1].text;
                        ParseNode_Expr(context, innode.children[0], out math.left);
                        ParseNode_Expr(context, innode.children[2], out math.right);
                        math.isConst = math.left.isConst && math.right.isConst;
                        outnode = math;
                    }
                    return;
                case "expr_group":
                    {
                        ParseNode_Expr(context, innode.children[1], out outnode);
                    }
                    return;

                case "expr_cond":
                    {
                        var math = new Node_Expr_Math3Op();
                        ParseNode_Expr(context, innode.children[0], out math.condition);
                        ParseNode_Expr(context, innode.children[2], out math.vTrue);
                        ParseNode_Expr(context, innode.children[4], out math.vFalse);
                        math.isConst = math.condition.isConst && math.vTrue.isConst && math.vFalse.isConst;
                        outnode = math;
                    }
                    return;
                case "expr_unary":
                    {
                        if (innode.children[0].text == "-" && isConst(innode.children[1]))
                        {
                            ParseNode_Number(context, innode.children[1], out Node_Expr_Number _node, true);
                            outnode = _node;
                        }
                        else
                        {
                            ParseNode_Expr(context, innode.children[1], out Node_Expr expr);
                            var token = innode.children[0].text;
                            var unary = new Node_Expr_Unary(token, expr);
                            outnode = unary;
                        }
                    }
                    return;
                case "expr_postfix":
                    {//後綴表達式 包括1. ++ -- 這樣的自運算  2.call  3.數組 4.member
                        if (innode.children.Count == 2)
                        {

                        }
                        if (innode.children[1].text == "(")//call
                        {
                            ParseNode_Expr_Call(context, innode, out Node_Expr_Call _nodecall);
                            outnode = _nodecall;
                            return;
                        }
                        if (innode.children[1].text == ".")//member
                        {
                            compiler_expr.ParseNode_Expr_Member(context, innode, out outnode);
                            return;
                        }
                        if (innode.children[1].text == "[")//array
                        {
                            ParseNode_Expr(context, innode.children[0], out Node_Expr body);
                            Node_Expr[] indexs = new Node_Expr[(innode.children.Count - 2) / 2];
                            for (var i = 2; i < innode.children.Count - 1; i += 2)
                            {
                                ParseNode_Expr(context, innode.children[0], out Node_Expr exprindex);
                                indexs[(i - 2) / 2] = exprindex;
                            }
                            var array = new Node_Expr_Array(body, indexs);
                            outnode = array;
                            return;
                        }
                    }
                    throw new NotSupportedException();
                case "expr_new":
                    {
                        ParseNode_Expr_New(context, innode, out Node_Expr_New _nodecall);
                        outnode = _nodecall;
                    }
                    return;
                case "expr_cast":
                    {
                        ParseNode_Expr_Cast(context, innode, out Node_Expr_Cast _nodecast);
                        outnode = _nodecast;
                    }
                    return;
                default:
                    throw new Exception("not supported.");
            }


        }
        public static void ParseNode_ID_OnlyExpr(CompilerContext context, src.AstNode innode, out node.Node_Expr outnode)
        {
            var id = innode.text;
            if (context.FindTempVar(id, out TempVarContext v))
            {
                var tempvar = new Node_Expr_TempVar();
                tempvar.id = v;
                outnode = tempvar;
                //tempvar
                return;
            }
            if (context.FindMethod(id, out semantic.TTMethod method))
            {
                var tempvar = new Node_Expr_Method();
                tempvar.method = method;
                outnode = tempvar;
                return;
            }
            if (context.FindType(id, out semantic.TTType type))
            {
                var tempvar = new Node_Expr_Container();
                tempvar.container = type;
                outnode = tempvar;
                return;
            }
            if (context.FindNameSpace(id, out semantic.TTNameSpace _name))
            {
                var tempvar = new Node_Expr_Container();
                tempvar.container = _name;
                outnode = tempvar;
                return;

            }
            if(context.FindArg(id,out semantic.TTArg _arg))
            {
                var tempvar = new Node_Expr_Arg();
                tempvar.arg = _arg;
                outnode = tempvar;
                return;
            }
            throw new NotImplementedException();

        }

        public static void ParseNode_IDChain_OnlyExpr(CompilerContext context, src.AstNode innode, out node.Node_Expr outnode)
        {
            //能作爲表達式的idchain,
            //可能是type,
            //可能是臨時變量
            //可能是成員變量
            //可能是以上的組合，這些全都以來使用上下文來解釋
            if (innode.children.Count == 1 && innode.children[0].type == "ID")
            {
                ParseNode_ID_OnlyExpr(context, innode, out outnode);
                return;


            }

            if (innode.children.Count >= 3) //a.b
            {
                //去掉最后一节，先接着解，然后变成一个组合表达式
                var inleft = innode.Cut(0, innode.children.Count - 2);
                var inright = innode.children[innode.children.Count - 1];

                // 因为有namespace这一类可以套很深的表达式， idchain表达式 可能是 [namespace.]*.[type.]*.[var|method];
                //所以左值应该递归
                ParseNode_IDChain_OnlyExpr(context, inleft, out Node_Expr outleft);
                //ParseNode_ID_OnlyExpr(context, inleft, out node.Node_Expr outleft);
                if (outleft is node.Node_Expr_TempVar tempvar)
                {
                    Node_Expr_Member member = new Node_Expr_Member();
                    member.left = tempvar;
                    //member.membername = inright.text;
                    var tttype = tempvar.id.type;
                    tttype.FindMember(inright.text, out var _vm);
                    if (_vm == null)
                        throw new Exception("should not null.");
                    member.member = _vm;
                    outnode = member;

                    ////临时变量.b
                    ////有两个可能性，成员变量货成员函数，都是成员访问
                    return;

                }
                if (outleft is node.Node_Expr_Container container) //Type.xxx // static member or type.type typechain
                {
                    //先看看是不是成员访问
                    if (container.container.FindMember(inright.text, out var _vm))
                    {
                        Node_Expr_Member member = new Node_Expr_Member();
                        member.left = container;
                        member.member = _vm;
                        outnode = member;
                        return;
                    }
                    if (container.container.FindSubContainer(inright.text, out var _sc))
                    {
                        Node_Expr_Container newcontainer = new Node_Expr_Container();
                        newcontainer.container = _sc;
                        outnode = newcontainer;
                        return;
                    }
                }
                throw new NotImplementedException();

            }
            throw new NotImplementedException();

        }
        public static void ParseNode_Expr_Call(CompilerContext context, src.AstNode innode, out node.Node_Expr_Call outnode)
        {
            //Call节点也是很复杂的，左表达式可以很复杂，如果左表达式很简单，则说明是单纯的函数调用
            var callpart = innode;
            bool ismember = false;
            if (callpart.type == "expr")
            {
                if (callpart.children.Count == 3 && callpart.children[1].text == ".")
                    ismember = true;
                callpart = innode.children[innode.children.Count - 1];
            }
            if (callpart.type == "expr")
                callpart = callpart.children[0];

            outnode = new Node_Expr_Call();
            if (!ismember)
            {
                //简单调用的情况

                ParseNode_Expr(context, callpart.children[0], out outnode.function);//函数用0表达式解析
            }
            else
            {
                ParseNode_Expr_Member(context, innode, out outnode.function);//函数用0表达式解析
            }
            //1= (
            outnode.args = new List<Node_Expr>();
            var args = callpart.children[2];
            if (args.text != ")")
            {
                for (var i = 0; i < args.children.Count; i += 2)
                {
                    //i=arg
                    //i+1=","|')"
                    ParseNode_Expr(context, args.children[i], out var _arg);
                    outnode.args.Add(_arg);
                }
            }

            return;

        }
        public static void ParseNode_Expr_New(CompilerContext context, src.AstNode innode, out node.Node_Expr_New outnode)
        {
            //Call节点也是很复杂的，左表达式可以很复杂，如果左表达式很简单，则说明是单纯的函数调用

            outnode = new Node_Expr_New();
            ParseNode_Expr(context, innode.children[1], out var expr);//函数用1表达式解析
            if (expr is Node_Expr_Container v)
            {
                outnode.tttype = v.container as semantic.TTType;
            }
            else
            {
                throw new Exception("not a ctor call");
            }
            //1= (
            outnode.args = new List<Node_Expr>();
            var args = innode.children[3];
            if (args.text!=")")//==4有个0参的情况
            {
                for (var i = 0; i < args.children.Count; i += 2)
                {
                    //i=arg
                    //i+1=","|')"
                    ParseNode_Expr(context, args.children[i], out var _arg);
                    outnode.args.Add(_arg);
                }
            }

            return;

        }
        public static void ParseNode_Expr_Cast(CompilerContext context, src.AstNode innode, out node.Node_Expr_Cast outnode)
        {
            outnode = new Node_Expr_Cast();
            ParseNode_Expr(context, innode.children[1], out var typeexpr);//函数用1表达式解析
            ParseNode_Expr(context, innode.children[3], out var srcexpr);

            if (typeexpr is Node_Expr_Container v)
            {
                outnode.tttype = v.container as semantic.TTType;
            }
            else
            {
                throw new Exception("not a ctor call");
            }
            outnode.srcexpr = srcexpr;
            return;
        }
    }
}
